package com.zatech.cgnci.project.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zatech.cgnci.project.base.constant.ClaimConstant;
import com.zatech.cgnci.project.base.context.UserContext;
import com.zatech.cgnci.project.base.enums.*;
import com.zatech.cgnci.project.base.exception.GlobalException;
import com.zatech.cgnci.project.base.utils.ConvertUtils;
import com.zatech.cgnci.project.base.utils.VerifyUtils;
import com.zatech.cgnci.project.dto.*;
import com.zatech.cgnci.project.entity.*;
import com.zatech.cgnci.project.mapper.*;
import com.zatech.cgnci.project.service.*;
import com.zatech.cgnci.project.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.StopWatch;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class CgnciClaimCaseTaskServiceImpl extends ServiceImpl<CgnciClaimCaseTaskMapper, CgnciClaimCaseTaskDO> implements CgnciClaimCaseTaskService {
    @Resource
    private CgnciCodeTypeService cgnciCodeTypeService;
    @Resource
    private CgnciClaimCaseMapper cgnciClaimCaseMapper;
    @Resource
    private IApprovalService approvalService;
    @Resource
    private CgnciApprovalInfoMapper approvalInfoMapper;
    @Resource
    private CgnciApprovalRecordMapper approvalRecordMapper;
    @Resource
    private CgnciBusinessInsuranceService policyService;
    @Resource
    @Autowired
    private CgnciClaimReserveService claimReserveService;
    @Resource
    private CgnciAccessoryService accessoryService;
    @Resource
    private CgnciClaimPolicyTaskMapper claimPolicyTaskMapper;
    @Resource
    private CgnciClaimCaseTaskMapper cgnciClaimCaseTaskMapper;
    @Resource
    private CgnciClaimAlertInfoTaskService claimAlertInfoTaskService;
    @Resource
    private CgnciClaimCaseService cgnciClaimCaseService;
    @Resource
    private CgnciClaimSettlementTaskService cgnciClaimSettlementTaskService;
    @Autowired
    private CgnciClaimSettlementMapper claimSettlementMapper;
    @Resource
    private CgnciClaimReopenMapper cgnciClaimReopenMapper;
    @Autowired
    private CgnciApprovalConfigMapper approvalConfigMapper;
    @Resource
    private CgnciAccessoryMapper cgnciAccessoryMapper;
    @Resource
    private CgnciClaimReserveMapper reserveMapper;
    @Resource
    private CgnciClaimReserveTaskMapper reserveTaskMapper;
    @Resource
    private CgnciClaimReserveDetailMapper reserveDetailMapper;
    @Autowired
    private CgnciClaimSettlementTaskMapper claimSettlementTaskMapper;
    @Autowired
    private CgnciClaimSettlementReinsurerTaskMapper settlementReinsurerTaskMapper;
    @Autowired
    private CgnciClaimSettlementDetailTaskMapper settlementDetailTaskMapper;
    @Autowired
    private CgnciClaimReserveDetailTaskMapper reserveDetailTaskMapper;
    @Autowired
    private CgnciClaimAlertInfoService cgnciClaimAlertInfoService;
    @Resource
    CgnciApprovalConfigRoleUserService approvalConfigRoleUserService;

    @Autowired
    private CgnciOperationLogsService cgnciOperationLogsService;

    private static final List<String> excludeCaseStatusList = Arrays.asList(ClaimCaseStatusEnum.LOG_OFF.getCode(),
            ClaimCaseStatusEnum.CLOSE.getCode());

    @Override
    @Transactional(rollbackFor = Exception.class)
    public CgnciClaimCaseCreateResultVO createCase(String policyNo, Boolean confirm) {
        // 查询保单信息
        CgnciBusinessInsuranceMainVO policyInfo = policyService.getPolicyInfo(policyNo);
        if (policyInfo == null || Objects.isNull(policyInfo.getBusinessInsuranceVO())) {
            return null;
        }

        CgnciClaimCaseCreateResultVO caseCheckPass = createCaseCheckPass(policyInfo, confirm);
        if (CollectionUtils.isNotEmpty(caseCheckPass.getConfirmMessageList())) {
            return caseCheckPass;
        }
        UserEntity user = UserContext.getUser();


        CgnciClaimCaseTaskDO task = buildCreate(user, policyInfo);
        task.setProjectName(caseCheckPass.getProjectName());
        // 保存案件任务
        this.save(task);

        // 创建案件
        CgnciClaimCaseDO convertInsert = ConvertUtils.convert(task, CgnciClaimCaseDO.class);
        String taskNo = task.getTaskNo();
        String caseNo = task.getCaseNo();
        convertInsert.setCaseId(null);
        convertInsert.setCreator(user.getNameAndCode());
        convertInsert.setUpdater(user.getNameAndCode());
        List<CgnciApprovalConfigRoleUserDO> list = approvalConfigRoleUserService.listCreateUser("新增立案审核任务", "发起人", user.getUsercode());
        if (VerifyUtils.isNotEmpty(list)) {
            // 添加代理人，目的是为了工作台中代理人也可以查到当前任务
            convertInsert.setCurrentAgentAndName(list.stream().map(value -> value.getCurrentApproverName() + "-" + value.getCurrentApprover()).collect(Collectors.joining(",")));
        }
        cgnciClaimCaseMapper.insert(convertInsert);

        // 创建案件流程
        createCaseFlow(user, task);

        // 保存保单信息
        saveCasePolicyInfo(policyInfo, task);

        // 保存日志
        String content = String.format("立案号：%s;立案任务号：%s", caseNo, taskNo);
        saveLog(caseNo, OperationTypeEnum.CREATE_CASE, user.getUsername(), content);

        caseCheckPass.setTaskNo(taskNo);
        caseCheckPass.setCaseNo(caseNo);
        return caseCheckPass;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveClaimCaseTask(CgnciClaimCaseAddDTO req) {
        validateSave(req);
        CgnciClaimCaseTaskDO caseTaskDO = getBaseMapper().selectByTaskNo(req.getTaskNo());
        Assert.notNull(caseTaskDO, StringUtils.join(req.getTaskNo(), "案件任务不存#saveClaimCaseTask"));
        Assert.isTrue(Objects.equals(req.getCaseNo(), caseTaskDO.getCaseNo()), "请输入正确的案件号。");
        Assert.isTrue(Objects.equals(req.getPolicyNo(), caseTaskDO.getPolicyNo()), "请输入正确的保单号。");
        Assert.hasText(req.getSaveType(), "保存类型必填。");
        UserEntity user = UserContext.getUser();
        saveCaseTask(user, req, caseTaskDO);
        cgnciClaimCaseService.synSaveClaimCase(req);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void submitCase(String taskNo) {
        UserEntity user = UserContext.getUser();
        CgnciClaimCaseTaskDO claimCaseTask = getCaseTask(taskNo);
        Assert.notNull(claimCaseTask, StringUtils.join(taskNo, "查询不到案件"));
        if (ClaimTaskStatusEnum.CHECKING.getCode().equals(claimCaseTask.getTaskStatus())) {
            saveErrorMessage(taskNo, "任务审核中。", BusinessScenariosTypeEnum.CLAIM_CASE.getCode(), ContentInfoTypeEnum.ERROR.getCode());
            throw new GlobalException(ResponseCodeEnum.PARAMS_ILLEGAL, "任务审核中...");
        }
        if (ClaimTaskStatusEnum.DONE.getCode().equals(claimCaseTask.getTaskStatus())) {
            saveErrorMessage(taskNo, "当前任务已完成,不能再次提交审核。", BusinessScenariosTypeEnum.CLAIM_CASE.getCode(), ContentInfoTypeEnum.ERROR.getCode());
            throw new GlobalException(ResponseCodeEnum.PARAMS_ILLEGAL, "当前任务已完成,不能再次提交审核。");
        }
        List<CgnciClaimCaseDO> count = cgnciClaimCaseMapper.selectList(new LambdaQueryWrapper<CgnciClaimCaseDO>()
                .eq(CgnciClaimCaseDO::getCaseName, claimCaseTask.getCaseName())
                .ne(CgnciClaimCaseDO::getCaseStatus, ClaimCaseStatusEnum.LOG_OFF.getCode()));
        if (CollectionUtils.isNotEmpty(count)) {
            String caseNoList = count.stream().map(CgnciClaimCaseDO::getCaseNo).collect(Collectors.joining(ClaimConstant.SEMICOLON));
            saveErrorMessage(taskNo, String.format("案件名称在立案号%s已存在，请修改。", caseNoList), BusinessScenariosTypeEnum.CLAIM_CASE.getCode(), ContentInfoTypeEnum.ERROR.getCode());
        }
        FlowTaskSubmitDTO flowTask = new FlowTaskSubmitDTO();
        flowTask.setFormId(taskNo);
        CgnciClaimCaseTaskDO updateTask = new CgnciClaimCaseTaskDO();
        updateTask.setCaseId(claimCaseTask.getCaseId());
        updateTask.setTaskStatus(ClaimTaskStatusEnum.CHECKING.getCode());
        updateTask.setUpdateTime(new Date());
        updateTask.setUpdater(user.getNameAndCode());
        getBaseMapper().updateById(updateTask);
        approvalService.submit(flowTask);
        saveLog(claimCaseTask.getCaseNo(), OperationTypeEnum.SUBMIT_CASE, user.getUsername());
    }


    @Override
    public void approveCase(CgnciClaimCaseCheckDTO req) {
        UserEntity user = UserContext.getUser();
        String taskNo = req.getTaskNo();
        CgnciClaimCaseTaskDO claimCaseTask = getCaseTask(taskNo);
        Assert.notNull(claimCaseTask, StringUtils.join(taskNo, "查询不到案件"));
        if (!ClaimTaskStatusEnum.CHECKING.getCode().equals(claimCaseTask.getTaskStatus())) {
            throw new GlobalException(ResponseCodeEnum.PARAMS_ILLEGAL, "任务状态错误,不在审核中.");
        }
        // 审批流
        FlowTaskApprovalDTO flowTask = new FlowTaskApprovalDTO();
        flowTask.setFormId(taskNo);
        flowTask.setFormNo(taskNo);
        flowTask.setApproverOpinions(req.getReviewComments());
        FlowTaskVO approve = approvalService.approve(flowTask);
        // 更新业务数据
        CgnciClaimCaseTaskDO updateTask = new CgnciClaimCaseTaskDO();
        updateTask.setCaseId(claimCaseTask.getCaseId());
        updateTask.setReviewComments(req.getReviewComments());
        if (ClaimTaskStatusEnum.DONE.getCode().equals(approve.getStatus())) {
            updateTask.setTaskStatus(ClaimTaskStatusEnum.DONE.getCode());
            updateTask.setCaseStatus(ClaimCaseStatusEnum.CLAIM.getCode());
            updateTask.setReviewComments(req.getReviewComments());
            updateTask.setUpdateTime(new Date());
            updateTask.setUpdater(user.getNameAndCode());
            getBaseMapper().updateById(updateTask);
            cgnciClaimCaseMapper.updateCaseStatus(claimCaseTask.getCaseNo(), ClaimCaseStatusEnum.CLAIM.getCode());

        } else {
            updateTask.setTaskStatus(approve.getStatus());
            getBaseMapper().updateById(updateTask);
        }
        saveLog(claimCaseTask.getCaseNo(), OperationTypeEnum.CASE_TASK_PASS, user.getUsername(), req.getReviewComments());
    }

    @Override
    public void backCase(CgnciClaimCaseCheckDTO req) {
        UserEntity user = UserContext.getUser();
        String taskNo = req.getTaskNo();
        CgnciClaimCaseTaskDO claimCaseTask = getCaseTask(taskNo);
        Assert.notNull(claimCaseTask, StringUtils.join(taskNo, "查询不到案件任务。"));
        FlowTaskBackDTO flowTask = new FlowTaskBackDTO();
        // 需要指定退回节点
        flowTask.setApprovalNode(req.getApprovalNode());
        flowTask.setFormId(taskNo);
        flowTask.setFormNo(taskNo);
        flowTask.setApproverOpinions(req.getReviewComments());
        FlowTaskVO back = approvalService.back(flowTask);
        CgnciClaimCaseTaskDO updateTask = new CgnciClaimCaseTaskDO();
        updateTask.setCaseId(claimCaseTask.getCaseId());
        updateTask.setTaskStatus(back.getStatus());
        updateTask.setReviewComments(req.getReviewComments());
        updateTask.setUpdateTime(new Date());
        updateTask.setUpdater(user.getNameAndCode());
        getBaseMapper().updateById(updateTask);
        String msg = req.getReviewComments();
        if (ClaimTaskTypeEnum.REOPEN.getCode().equals(claimCaseTask.getTaskType())) {
            saveLog(claimCaseTask.getCaseNo(), OperationTypeEnum.REOPEN_TASK_BACK, user.getUsername(), msg);
        } else {
            saveLog(claimCaseTask.getCaseNo(), OperationTypeEnum.CASE_TASK_BACK, user.getUsername(), msg);
        }
    }

    @Override
    public void logOffCase(String taskNo) {
        CgnciClaimCaseTaskDO claimCaseTask = getCaseTask(taskNo);
        Assert.notNull(claimCaseTask, StringUtils.join(taskNo, "查询不到案件"));
        if (!ClaimTaskStatusEnum.INPUT.getCode().equals(claimCaseTask.getTaskStatus()) &&
                !ClaimTaskStatusEnum.BACK.getCode().equals(claimCaseTask.getTaskStatus())) {
            throw new GlobalException(ResponseCodeEnum.PARAMS_ILLEGAL, "非录入中，不可注销.");
        }
        UserEntity user = UserContext.getUser();
        FlowTaskCancelDTO flowTask = new FlowTaskCancelDTO();
        flowTask.setFormId(taskNo);
        flowTask.setFormNo(taskNo);
        approvalService.cancelTask(flowTask);
        CgnciClaimCaseTaskDO updateTask = new CgnciClaimCaseTaskDO();
        updateTask.setCaseId(claimCaseTask.getCaseId());
        updateTask.setTaskStatus(ClaimTaskStatusEnum.LOG_OFF.getCode());
        updateTask.setCaseStatus(ClaimCaseStatusEnum.LOG_OFF.getCode());
        updateTask.setUpdateTime(new Date());
        updateTask.setUpdater(user.getNameAndCode());
        getBaseMapper().updateById(updateTask);
        cgnciClaimCaseMapper.updateCaseStatus(claimCaseTask.getCaseNo(), ClaimCaseStatusEnum.LOG_OFF.getCode());
        saveLog(claimCaseTask.getCaseNo(), OperationTypeEnum.CANCEL_CASE, user.getUsername());
    }

    @Override
    public CgnciClaimCaseReopenVO reopenCase(CgnciClaimCaseReopenDTO req) {
        textMaxLength(req.getApplyReason());
        String caseNo = req.getCaseNo();
        CgnciClaimCaseDO claimCase = getCase(caseNo);
        Assert.notNull(claimCase, StringUtils.join(caseNo, "立案号不存在。"));
        if (!ClaimCaseStatusEnum.CLOSE.getCode().equals(claimCase.getCaseStatus())) {
            throw new GlobalException(ResponseCodeEnum.PARAMS_ILLEGAL, "案件未结案，不可重开。");
        }

        CgnciClaimCaseReopenVO result = CgnciClaimCaseReopenVO.builder().build();
        if (Objects.isNull(req.getReopenId())) {
            createReopenCase(req, result);
        } else {
            saveReopenCase(req, result);
        }
        return result;
    }

    private void saveReopenCase(CgnciClaimCaseReopenDTO req, CgnciClaimCaseReopenVO result) {
        UserEntity user = UserContext.getUser();
        CgnciClaimReopenDO cgnciClaimReopenDO = cgnciClaimReopenMapper.selectById(req.getReopenId());
        if (VerifyUtils.isEmpty(cgnciClaimReopenDO)) {
            throw new GlobalException(ResponseCodeEnum.PARAMS_ILLEGAL, "reopenId有误");
        }
        cgnciClaimReopenDO.setApplyReason(req.getApplyReason());
        cgnciClaimReopenDO.setUpdater(user.getNameAndCode());
        cgnciClaimReopenDO.setUpdateTime(new Date());
        cgnciClaimReopenMapper.updateById(cgnciClaimReopenDO);
        result.setTaskNo(cgnciClaimReopenDO.getTaskNo());
    }

    private void createReopenCase(CgnciClaimCaseReopenDTO req, CgnciClaimCaseReopenVO result) {
        UserEntity user = UserContext.getUser();
        String caseNo = req.getCaseNo();
        // 规则：案件生成的收款和支付记录必须都为“已结算”； 提示语：案件包含未结算的收款或支付记录，不可重开。
        List<String> list = Arrays.asList(ClaimTaskStatusEnum.INPUT.getCode(), ClaimTaskStatusEnum.CHECKING.getCode());
        LambdaQueryWrapper<CgnciClaimReopenDO> param = new LambdaQueryWrapper<CgnciClaimReopenDO>()
                .eq(CgnciClaimReopenDO::getCaseNo, req.getCaseNo()).in(CgnciClaimReopenDO::getTaskStatus, list);
        Integer count = cgnciClaimReopenMapper.selectCount(param);
        if (Objects.nonNull(count) && count > 0) {
            throw new GlobalException(ResponseCodeEnum.PARAMS_ILLEGAL, "当前任务:录入中/审核中,不支持再次发起重开");
        }
        CgnciClaimCaseTaskDO caseTask = copyCreateCaseTask(user, caseNo, null, ClaimTaskTypeEnum.REOPEN.getCode());
        CgnciClaimReopenDO insertParam = new CgnciClaimReopenDO();
        String taskNo = caseTask.getTaskNo();
        insertParam.setCaseNo(caseNo);
        insertParam.setTaskNo(taskNo);
        insertParam.setApplicant(user.getNameAndCode());
        insertParam.setApplyReason(req.getApplyReason());
        insertParam.setTaskStatus(ClaimTaskStatusEnum.INPUT.getCode());
        insertParam.setDeleted(YesOrNoEnum.NO.getCode());
        insertParam.setCreator(user.getNameAndCode());
        insertParam.setUpdater(user.getNameAndCode());
        cgnciClaimReopenMapper.insert(insertParam);
        createCaseFlow(user, caseTask);
        result.setTaskNo(taskNo);
    }


    @Override
    public void approveReopenCase(CgnciClaimCaseReopenDTO req) {
        String taskNo = req.getTaskNo();
        CgnciClaimCaseTaskDO claimCaseTask = getCaseTask(taskNo);
        Assert.notNull(claimCaseTask, StringUtils.join(taskNo, "查询不到案件"));
        if (!ClaimTaskStatusEnum.CHECKING.getCode().equals(claimCaseTask.getTaskStatus())) {
            throw new GlobalException(ResponseCodeEnum.PARAMS_ILLEGAL, "审核中才能操作.");
        }
        UserEntity user = UserContext.getUser();
        // 审批流
        FlowTaskApprovalDTO flowTask = new FlowTaskApprovalDTO();
        flowTask.setFormId(taskNo);
        flowTask.setFormNo(taskNo);
        flowTask.setApproverOpinions(req.getReviewComments());
        FlowTaskVO approve = approvalService.approve(flowTask);
        // 更新业务数据
        CgnciClaimCaseTaskDO updateTask = new CgnciClaimCaseTaskDO();
        updateTask.setCaseId(claimCaseTask.getCaseId());
        updateTask.setReviewComments(req.getReviewComments());

        if (ClaimTaskStatusEnum.DONE.getCode().equals(approve.getStatus())) {
            updateTask.setTaskStatus(ClaimTaskStatusEnum.DONE.getCode());
            updateTask.setCaseStatus(ClaimCaseStatusEnum.REOPEN.getCode());
            updateTask.setReviewComments(req.getReviewComments());
            updateTask.setUpdateTime(new Date());
            updateTask.setUpdater(user.getNameAndCode());
            getBaseMapper().updateById(updateTask);
            cgnciClaimCaseMapper.updateCaseStatus(claimCaseTask.getCaseNo(), ClaimCaseStatusEnum.REOPEN.getCode());
            //任务回退到录入中
            updateOldCaseTask(claimCaseTask.getCaseNo());
        } else {
            updateTask.setTaskStatus(approve.getStatus());
            getBaseMapper().updateById(updateTask);
        }
        String msg = req.getReviewComments();
        saveLog(claimCaseTask.getCaseNo(), OperationTypeEnum.REOPEN_TASK_PASS, user.getUsername(), msg);
    }

    private void updateOldCaseTask(String caseNo) {
        CgnciClaimCaseTaskDO caseTaskDO = cgnciClaimCaseTaskMapper.selectOne(new LambdaQueryWrapper<CgnciClaimCaseTaskDO>()
                .eq(CgnciClaimCaseTaskDO::getCaseNo, caseNo)
                .eq(CgnciClaimCaseTaskDO::getTaskType, ClaimTaskTypeEnum.FILING.getCode()));
        if (Objects.nonNull(caseTaskDO)) {
            CgnciApprovalInfoDO updateInfoDO = new CgnciApprovalInfoDO();
            updateInfoDO.setIsEnd(0);
            updateInfoDO.setCurrentApproverAndName(caseTaskDO.getCreator());
            updateInfoDO.setFounderId(caseTaskDO.getCreator().split("-")[1]);
            updateInfoDO.setFounderName(caseTaskDO.getCreator().split("-")[0]);
            updateInfoDO.setApprovalNode(0);
            LambdaQueryWrapper<CgnciApprovalInfoDO> queryWrapper =
                    new LambdaQueryWrapper<CgnciApprovalInfoDO>()
                            .eq(CgnciApprovalInfoDO::getFormNo, caseTaskDO.getTaskNo());
            approvalInfoMapper.update(updateInfoDO, queryWrapper);
            // 更新业务数据
            CgnciClaimCaseTaskDO updateTask = new CgnciClaimCaseTaskDO();
            updateTask.setTaskStatus(ClaimTaskStatusEnum.INPUT.getCode());
            updateTask.setCaseStatus(ClaimCaseStatusEnum.REOPEN.getCode());
            LambdaQueryWrapper<CgnciClaimCaseTaskDO> conditionSettle =
                    new LambdaQueryWrapper<CgnciClaimCaseTaskDO>()
                            .eq(CgnciClaimCaseTaskDO::getTaskNo, caseTaskDO.getTaskNo());
            cgnciClaimCaseTaskMapper.update(updateTask, conditionSettle);
            //清空准备金计提调整之前的任务号
            reserveMapper.updateTaskNo(caseTaskDO.getCaseNo());
            //清空结算任务号
            claimSettlementMapper.updateTaskNo(caseTaskDO.getCaseNo());
        }
    }

    @Override
    public IPage<CgnciClaimCasePageWorkbenchVO> casePageTaskWorkbench(CgnciClaimCaseQueryDTO req) {
        return getBaseMapper().casePageTaskWorkbench(req.toPage(), req);
    }


    @Override
    public CgnciClaimCaseVO caseDetailTask(ClaimCaseTaskQueryOptionDTO<String> req) {
        // 基本信息
        CgnciClaimCaseTaskDO claimCaseTask = getCaseTask(req.getTaskNo());
        Assert.notNull(claimCaseTask, StringUtils.join(req.getTaskNo(), "查询不到案件"));
        CgnciClaimCaseVO claimCaseVO = ConvertUtils.convert(claimCaseTask, CgnciClaimCaseVO.class);
        String taskNo = claimCaseVO.getTaskNo();
        // 获取关联保单信息
        CgnciClaimPolicyTaskDO claimPolicy = claimPolicyTaskMapper.selectOne(
                new LambdaQueryWrapper<CgnciClaimPolicyTaskDO>()
                        .eq(CgnciClaimPolicyTaskDO::getTaskNo, taskNo));
        claimCaseVO.setClaimPolicy(ConvertUtils.convert(claimPolicy, CgnciClaimPolicyVO.class));
        // 获取附件信息
        List<CgnciAccessoryDO> accessoryList = accessoryService.list(new LambdaQueryWrapper<CgnciAccessoryDO>()
                .eq(CgnciAccessoryDO::getBusinessNo, taskNo));
        claimCaseVO.setAccessoryList(ConvertUtils.convert(accessoryList, CgnciAccessoryVO.class));
        if (req.isNeedSettlement()) {
            String businessNo = claimCaseVO.getCaseNo() + taskNo;
            claimCaseVO.setSettlements(cgnciClaimSettlementTaskService.settlementTaskListByBusinessNo(businessNo));
        }
        if (req.isNeedReopen()) {
            LambdaQueryWrapper<CgnciClaimReopenDO> queryReopen = new LambdaQueryWrapper<CgnciClaimReopenDO>()
                    .eq(CgnciClaimReopenDO::getTaskNo, taskNo)
                    .eq(CgnciClaimReopenDO::getDeleted, YesOrNoEnum.NO.getCode());
            claimCaseVO.setClaimReopen(ConvertUtils.convert(cgnciClaimReopenMapper.selectOne(queryReopen),
                    ClaimReopenVO.class));
        }
        //TODO 准备金代码注释 待运祥处理
        if (req.isNeedReserve()) {
            claimCaseVO.setReserveVO(claimReserveService.detailTask(taskNo));
        }
        return claimCaseVO;
    }


    private void saveCaseTask(UserEntity user, CgnciClaimCaseAddDTO req, CgnciClaimCaseTaskDO taskDO) {
        CgnciClaimCaseTaskDO task = new CgnciClaimCaseTaskDO();
        BeanUtils.copyProperties(req, task);
        task.setCaseId(taskDO.getCaseId());
        task.setUpdater(user.getNameAndCode());
        if (CaseSaveTypeEnum.CASE_INFO.getCode().equals(req.getSaveType())) {
            saveLog(taskDO.getCaseNo(), OperationTypeEnum.EDIT_CASE, user.getUsername());
        } else if (CaseSaveTypeEnum.LINK_INFO.getCode().equals(req.getSaveType())) {
            saveLog(taskDO.getCaseNo(), OperationTypeEnum.EDIT_CONTACT, user.getUsername());
        }
        updateById(task);
        task.setCreator(user.getNameAndCode());
        saveAttachment(req, task);
    }

    @Override
    public List<ApprovalConfigVO> listBackNode(String taskNo) {
//        CgnciClaimCaseTaskDO caseTask = getCaseTask(taskNo);
        CgnciApprovalInfoDO approvalInfo = approvalInfoMapper.selectOne(new LambdaQueryWrapper<CgnciApprovalInfoDO>()
                .eq(CgnciApprovalInfoDO::getFormId, taskNo)
                .eq(CgnciApprovalInfoDO::getFormNo, taskNo));
        if (VerifyUtils.isEmpty(approvalInfo)) {
            throw new GlobalException(ResponseCodeEnum.HTTP_REQUEST_SERVICE_ERROR, "任务不存在");
        }
        // 获取指定分组,小于某节点的所有节点
        List<CgnciApprovalConfigDO> CgnciApprovalConfigDOList = approvalConfigMapper.selectList(new LambdaQueryWrapper<CgnciApprovalConfigDO>()
                .eq(CgnciApprovalConfigDO::getGroupId, approvalInfo.getApprovalConfigGroupId())
                .lt(CgnciApprovalConfigDO::getApprovalNode, approvalInfo.getApprovalNode())
                .orderByDesc(CgnciApprovalConfigDO::getApprovalNode));
        return ConvertUtils.convert(CgnciApprovalConfigDOList, ApprovalConfigVO.class);
    }

    @Override
    public CgnciClaimCaseTaskCountVO caseTaskCount() {
        CgnciClaimCaseTaskCountVO cgnciClaimCaseTaskCountVO = new CgnciClaimCaseTaskCountVO();
        List<String> caseStatus = new ArrayList<>();
        caseStatus.add(ClaimCaseStatusEnum.CLOSE.getCode());
        caseStatus.add(ClaimCaseStatusEnum.LOG_OFF.getCode());
        UserEntity user = UserContext.getUser();
        Integer caseQuantity = cgnciClaimCaseMapper.selectCount(new LambdaQueryWrapper<CgnciClaimCaseDO>()
                .eq(CgnciClaimCaseDO::getCreator, user.getNameAndCode())
                .notIn(CgnciClaimCaseDO::getCaseStatus, caseStatus));
        List<String> taskStatus = new ArrayList<>();
        taskStatus.add(ClaimTaskStatusEnum.DONE.getCode());
        taskStatus.add(ClaimTaskStatusEnum.LOG_OFF.getCode());
        Integer taskQuantity = cgnciClaimCaseTaskMapper.selectCount(new LambdaQueryWrapper<CgnciClaimCaseTaskDO>()
                .eq(CgnciClaimCaseTaskDO::getCreator, user.getNameAndCode())
                .notIn(CgnciClaimCaseTaskDO::getTaskStatus, taskStatus));
        cgnciClaimCaseTaskCountVO.setCaseQuantity(caseQuantity);
        cgnciClaimCaseTaskCountVO.setTaskQuantity(taskQuantity);
        return cgnciClaimCaseTaskCountVO;
    }

    @Override
    public CgnciClaimCaseQuantityVO caseTaskQuantity() {
        UserEntity user = UserContext.getUser();
        return cgnciClaimCaseTaskMapper.getCaseCount(user.getNameAndCode());
    }

    @Override
    public CaseStatusCountVO caseStatusCount(String taskType) {
        UserEntity user = UserContext.getUser();
        return cgnciClaimCaseTaskMapper.caseStatusCount(user.getNameAndCode(), taskType);
    }

    @Override
    public void logOffReopenCase(String taskNo) {
        CgnciClaimCaseTaskDO claimCaseTask = getCaseTask(taskNo);
        Assert.notNull(claimCaseTask, StringUtils.join(taskNo, "查询不到案件"));
        if (!ClaimTaskStatusEnum.INPUT.getCode().equals(claimCaseTask.getTaskStatus())) {
            throw new GlobalException(ResponseCodeEnum.PARAMS_ILLEGAL, "非录入中，不可注销.");
        }
        UserEntity user = UserContext.getUser();
        FlowTaskCancelDTO flowTask = new FlowTaskCancelDTO();
        flowTask.setFormId(taskNo);
        flowTask.setFormNo(taskNo);
        approvalService.cancelTask(flowTask);
        CgnciClaimCaseTaskDO updateTask = new CgnciClaimCaseTaskDO();
        updateTask.setCaseId(claimCaseTask.getCaseId());
        updateTask.setTaskStatus(ClaimTaskStatusEnum.LOG_OFF.getCode());
        updateTask.setCaseStatus(ClaimCaseStatusEnum.LOG_OFF.getCode());
        updateTask.setUpdateTime(new Date());
        updateTask.setUpdater(user.getNameAndCode());
        getBaseMapper().updateById(updateTask);
        LambdaQueryWrapper<CgnciClaimReopenDO> condition =
                new LambdaQueryWrapper<CgnciClaimReopenDO>().eq(CgnciClaimReopenDO::getTaskNo, taskNo);
        CgnciClaimReopenDO updateReopen = new CgnciClaimReopenDO();
        updateReopen.setTaskStatus(ClaimTaskStatusEnum.LOG_OFF.getCode());
        updateReopen.setUpdateTime(new Date());
        updateReopen.setUpdater(user.getNameAndCode());
        cgnciClaimReopenMapper.update(updateReopen, condition);
        saveLog(claimCaseTask.getCaseNo(), OperationTypeEnum.CANCEL_REOPEN, user.getUsername());


    }

    @Override
    public void submitReopenCase(String taskNo) {
        UserEntity user = UserContext.getUser();
        CgnciClaimCaseTaskDO claimCaseTask = getCaseTask(taskNo);
        Assert.notNull(claimCaseTask, StringUtils.join(taskNo, "查询不到案件"));
        String caseNo = claimCaseTask.getCaseNo();
        if (ClaimTaskStatusEnum.CHECKING.getCode().equals(claimCaseTask.getTaskStatus())) {
            saveErrorMessage(caseNo, "任务审核中。", BusinessScenariosTypeEnum.CLAIM_REOPEN.getCode(), ContentInfoTypeEnum.ERROR.getCode());
            throw new GlobalException(ResponseCodeEnum.PARAMS_ILLEGAL, "任务审核中...");
        }
        if (ClaimTaskStatusEnum.DONE.getCode().equals(claimCaseTask.getTaskStatus())) {
            saveErrorMessage(taskNo, "当前任务已完成,不能再次提交审核。", BusinessScenariosTypeEnum.CLAIM_REOPEN.getCode(), ContentInfoTypeEnum.ERROR.getCode());
            throw new GlobalException(ResponseCodeEnum.PARAMS_ILLEGAL, "当前任务已完成,不能再次提交审核。");
        }
        List<CgnciClaimCaseDO> count = cgnciClaimCaseMapper.selectList(new LambdaQueryWrapper<CgnciClaimCaseDO>()
                .eq(CgnciClaimCaseDO::getCaseName, claimCaseTask.getCaseName())
                .ne(CgnciClaimCaseDO::getCaseStatus, ClaimCaseStatusEnum.LOG_OFF.getCode()));
        if (CollectionUtils.isNotEmpty(count)) {
            String caseNoList = count.stream().map(CgnciClaimCaseDO::getCaseNo).collect(Collectors.joining(ClaimConstant.SEMICOLON));
            saveErrorMessage(taskNo, String.format("案件名称在立案号%s已存在，请修改。", caseNoList), BusinessScenariosTypeEnum.CLAIM_REOPEN.getCode(), ContentInfoTypeEnum.ERROR.getCode());
        }
        FlowTaskSubmitDTO flowTask = new FlowTaskSubmitDTO();
        flowTask.setFormId(taskNo);
        CgnciClaimCaseTaskDO updateTask = new CgnciClaimCaseTaskDO();
        updateTask.setCaseId(claimCaseTask.getCaseId());
        updateTask.setTaskStatus(ClaimTaskStatusEnum.CHECKING.getCode());
        updateTask.setUpdateTime(new Date());
        updateTask.setUpdater(user.getNameAndCode());
        getBaseMapper().updateById(updateTask);
        approvalService.submit(flowTask);
        saveLog(claimCaseTask.getCaseNo(), OperationTypeEnum.SUBMIT_CASE, user.getUsername());
    }

    @Override
    public void caseAfterSave(CgnciClaimCaseAddDTO req) {
        validateSave(req);
        CgnciClaimCaseDO caseTaskDO = cgnciClaimCaseMapper.selectById(req.getCaseId());
        Assert.notNull(caseTaskDO, StringUtils.join(req.getCaseId(), "立案不存在"));
        Assert.isTrue(Objects.equals(req.getCaseNo(), caseTaskDO.getCaseNo()), "请输入正确的案件号。");
        Assert.isTrue(Objects.equals(req.getPolicyNo(), caseTaskDO.getPolicyNo()), "请输入正确的保单号。");
        UserEntity user = UserContext.getUser();
        if (CaseSaveTypeEnum.CASE_INFO.getCode().equals(req.getSaveType())) {
            CgnciClaimCaseDO task = new CgnciClaimCaseDO();
            BeanUtils.copyProperties(req, task);
            task.setCaseId(caseTaskDO.getCaseId());
            task.setCaseStatus(null);
            task.setContactName(null);
            task.setContactPhone(null);
            task.setContactEmail(null);
            task.setUpdater(user.getNameAndCode());
            task.setUpdateTime(new Date());
            saveLog(caseTaskDO.getCaseNo(), OperationTypeEnum.EDIT_CASE, user.getUsername());
            cgnciClaimCaseMapper.updateById(task);
        } else if (CaseSaveTypeEnum.LINK_INFO.getCode().equals(req.getSaveType())) {
            CgnciClaimCaseDO updateLink = new CgnciClaimCaseDO();
            updateLink.setCaseId(req.getCaseId());
            updateLink.setContactName(req.getContactName());
            updateLink.setContactPhone(req.getContactPhone());
            updateLink.setContactEmail(req.getContactEmail());
            updateLink.setUpdater(user.getNameAndCode());
            updateLink.setUpdateTime(new Date());
            cgnciClaimCaseMapper.updateById(updateLink);
            saveLog(caseTaskDO.getCaseNo(), OperationTypeEnum.EDIT_CONTACT, user.getUsername());
        }
    }

    @Override
    public void caseProcessCheck(String caseNo) {
        LambdaQueryWrapper<CgnciClaimCaseTaskDO> condition =
                new LambdaQueryWrapper<CgnciClaimCaseTaskDO>().eq(CgnciClaimCaseTaskDO::getCaseNo, caseNo)
                        .ne(CgnciClaimCaseTaskDO::getTaskStatus, ClaimTaskStatusEnum.DONE.getCode())
                        .eq(CgnciClaimCaseTaskDO::getDeleted, YesOrNoEnum.NO.getCode());
        List<CgnciClaimCaseTaskDO> taskDOList = cgnciClaimCaseTaskMapper.selectList(condition);
        if (CollectionUtils.isNotEmpty(taskDOList)) {
            for (CgnciClaimCaseTaskDO item : taskDOList) {
                if (!ClaimTaskStatusEnum.LOG_OFF.getCode().equals(item.getTaskStatus())) {
                    ClaimTaskTypeEnum typeEnum = ClaimTaskTypeEnum.getEnumByCode(item.getTaskType());
                    String msg = String.format("案件有%s-%s未完成，请先处理任务。", typeEnum.getName(), item.getTaskNo());
                    throw new GlobalException(ResponseCodeEnum.PARAMS_ILLEGAL, msg);
                }
            }
        }
    }


    @Override
    public List<CgnciClaimReopenVO> getReopenHistory(String caseNo) {
        LambdaQueryWrapper<CgnciClaimReopenDO> condition = new LambdaQueryWrapper<CgnciClaimReopenDO>()
                .eq(CgnciClaimReopenDO::getCaseNo, caseNo)
                .eq(CgnciClaimReopenDO::getDeleted, YesOrNoEnum.NO.getCode());
        List<CgnciClaimReopenDO> reopenDOList = cgnciClaimReopenMapper.selectList(condition);
        return ConvertUtils.convert(reopenDOList, CgnciClaimReopenVO.class);
    }


    private void validateSave(CgnciClaimCaseAddDTO param) {
        textMaxLength(param.getDeductibleDesc());
        textMaxLength(param.getClaimDesc());
        textMaxLength(param.getRemarks());
        Assert.notNull(param.getIsCatastrophe(), "是否巨灾案件必填.");
        if (param.getIsCatastrophe()) {
            Assert.hasText(param.getCatastropheName(), "巨灾名称必填.");
        }
        Assert.notNull(param.getCaseName(), "案件名称必填.");
        Assert.notNull(param.getRegisterDate(), "立案日期必填.");
        Assert.notNull(param.getNotifyDate(), "通知日期必填.");
        Assert.notNull(param.getAccidentDate(), "出险日期必填.");
        Assert.notNull(param.getOriginalCurrency(), "原始币种必填.");
        Assert.notNull(param.getSettlementCurrency(), "结算币种必填.");
        Assert.notNull(param.getReportCurrency(), "报损金额（币种）必填.");
        boolean reportResult = Objects.nonNull(param.getReportAmount())
                && BigDecimal.ZERO.compareTo(param.getReportAmount()) <= 0;
        Assert.isTrue(reportResult, "报损金额必填并且大于0");
        boolean estimateResult = Objects.nonNull(param.getEstimateAmount())
                && BigDecimal.ZERO.compareTo(param.getEstimateAmount()) <= 0;
        Assert.isTrue(estimateResult, "初步立案金额必填并且大于0");
        accidentDateValid(param); // 出险日期校验
        notifyDateValid(param); // 通知日期校验
        registerDateValid(param); // 立案日期校验
//        commonValid(param);
        CgnciBusinessInsuranceMainVO policy = policyService.getPolicyInfo(param.getPolicyNo());
        if (Objects.nonNull(policy) && Objects.nonNull(policy.getBusinessInsuranceVO())) {
            // 校验出险日期是否在保险期间内
            if (param.getAccidentDate().before(policy.getBusinessInsuranceVO().getStartDate()) ||
                    param.getAccidentDate().after(policy.getBusinessInsuranceVO().getEndDate())) {
                throw new GlobalException(ResponseCodeEnum.PARAMS_ILLEGAL, "出险日期不在保险期间内。");
            }
            // 校验在途批改
        }
        // 案件名称不得重复（状态为“已注销”的案件在校验范围内）
        LambdaQueryWrapper<CgnciClaimCaseDO> query = new LambdaQueryWrapper<CgnciClaimCaseDO>()
                .eq(CgnciClaimCaseDO::getCaseName, param.getCaseName())
                .ne(CgnciClaimCaseDO::getCaseStatus, ClaimCaseStatusEnum.LOG_OFF.getCode());
        if (Objects.nonNull(param.getCaseNo())) {
            // 不包含自己
            query.ne(CgnciClaimCaseDO::getCaseNo, param.getCaseNo());
        }
        Boolean alreadyExist = cgnciClaimCaseMapper.selectCount(query) < 1;
        Assert.isTrue(alreadyExist, "案件名称已存在。");
        // Assert.notEmpty(param.getAccessoryList(),"请上传相关附件");
    }

    private static void textMaxLength(String text) {
        if (Objects.isNull(text)) return;
        Assert.isTrue(text.length() <= 5000, "限5000字。");
    }


    private static void accidentDateValid(CgnciClaimCaseAddDTO param) {
        /*
         * -出险日期不得晚于出险日期止期；
         * -出险日期不得晚于通知日期；
         * -出险日期不得晚于立案日期；
         */
        if (param.getAccidentEndDate() != null && param.getAccidentDate().after(param.getAccidentEndDate())) {
            throw new GlobalException(ResponseCodeEnum.PARAMS_ILLEGAL, "出险日期不得晚于出险日期止期");
        }
        if (param.getAccidentDate().after(param.getNotifyDate())) {
            throw new GlobalException(ResponseCodeEnum.PARAMS_ILLEGAL, "出险日期不得晚于通知日期");
        }
        if (param.getAccidentDate().after(param.getRegisterDate())) {
            throw new GlobalException(ResponseCodeEnum.PARAMS_ILLEGAL, "出险日期不得晚于立案日期");
        }
    }

    private static void registerDateValid(CgnciClaimCaseAddDTO param) {
        /*
         * 立案日期不得早于出险日期；
         * 立案日期不得早于通知日期
         */
        if (param.getRegisterDate().before(param.getAccidentDate())) {
            throw new GlobalException(ResponseCodeEnum.PARAMS_ILLEGAL, "立案日期不得早于出险日期");
        }
        // 立案日期不得早于通知日期
        if (param.getRegisterDate().before(param.getNotifyDate())) {
            throw new GlobalException(ResponseCodeEnum.PARAMS_ILLEGAL, "立案日期不得早于通知日期");
        }
    }

    private static void notifyDateValid(CgnciClaimCaseAddDTO param) {
        /*
         * 通知日期不得早于出险日期；
         * 通知日期不得晚于立案日期
         */
        if (param.getNotifyDate().before(param.getAccidentDate())) {
            throw new GlobalException(ResponseCodeEnum.PARAMS_ILLEGAL, "通知日期不得早于出险日期");
        }
        // 通知日期不能晚于立案日期
        if (param.getNotifyDate().after(param.getRegisterDate())) {
            throw new GlobalException(ResponseCodeEnum.PARAMS_ILLEGAL, "通知日期不能晚于立案日期");
        }
    }


    private String generateCaseNo() {
        CgnciCodeTypeDO cgnciCodeTypeDO = cgnciCodeTypeService.getOne(new LambdaQueryWrapper<CgnciCodeTypeDO>()
                .eq(CgnciCodeTypeDO::getCodeHigherLevelCode, "claims")
                .eq(CgnciCodeTypeDO::getCodeName, "number"));
        String codeCode = cgnciCodeTypeDO.getCodeCode();
        int nextCodeCode = Integer.parseInt(codeCode) + 1;
        cgnciCodeTypeDO.setCodeCode(String.valueOf(nextCodeCode));
        cgnciCodeTypeService.updateById(cgnciCodeTypeDO);
        return StringUtils.join(ClaimConstant.C, nextCodeCode);
    }


    @Override
    public String generateTaskNo() {
        CgnciCodeTypeDO cgnciCodeTypeDO = cgnciCodeTypeService.getOne(new LambdaQueryWrapper<CgnciCodeTypeDO>()
                .eq(CgnciCodeTypeDO::getCodeHigherLevelCode, "claims-task")
                .eq(CgnciCodeTypeDO::getCodeName, "number"));
        String codeCode = cgnciCodeTypeDO.getCodeCode();
        int nextCodeCode = Integer.parseInt(codeCode) + 1;
        cgnciCodeTypeDO.setCodeCode(String.valueOf(nextCodeCode));
        cgnciCodeTypeService.updateById(cgnciCodeTypeDO);
        return StringUtils.join(ClaimConstant.T, nextCodeCode);
    }


    private void saveAttachment(CgnciClaimCaseAddDTO req, CgnciClaimCaseTaskDO task) {
        if (CollectionUtils.isEmpty(req.getAccessoryList())) return;
        req.getAccessoryList().forEach(accessory -> {
            CgnciAccessoryDO accessoryDO = accessoryService.getById(accessory.getAccId());
            if (VerifyUtils.isEmpty(accessoryDO)) {
                throw new GlobalException(ResponseCodeEnum.PARAMS_ILLEGAL, "文件id有误");
            }
            accessoryDO.setBusinessId(task.getCaseId());
            accessoryDO.setBusinessNo(task.getTaskNo());
            accessoryDO.setUploadNode(ClaimFlowEnum.CLAIM_CASE.getCode());
            accessoryDO.setUpdateUser(task.getUpdater());
            accessoryService.updateById(accessoryDO);
        });
    }

    private void saveAlterInfo(CgnciClaimCaseAddDTO req, CgnciClaimCaseTaskDO task) {
        if (CollectionUtils.isEmpty(req.getAlertInfoList())) return;
        for (CgnciClaimAlertInfoDTO alertInfo : req.getAlertInfoList()) {
            CgnciClaimAlertInfoTaskDO alertInfoDO = new CgnciClaimAlertInfoTaskDO();
            alertInfoDO.setAlertId(alertInfo.getAlertId());
            alertInfoDO.setTaskNo(task.getTaskNo());
            alertInfoDO.setCaseNo(task.getCaseNo());
            alertInfoDO.setAlertType(alertInfo.getAlertType());
            alertInfoDO.setContent(alertInfo.getContent());
            if (Objects.isNull(alertInfo.getAlertId())) {
                claimAlertInfoTaskService.save(alertInfoDO);
            } else {
                claimAlertInfoTaskService.updateById(alertInfoDO);
            }
        }
    }

    private void saveCasePolicyInfo(CgnciBusinessInsuranceMainVO policyInfo, CgnciClaimCaseTaskDO task) {
        CgnciClaimPolicyTaskDO claimPolicyDO = claimPolicyTaskMapper.selectOne(
                new LambdaQueryWrapper<CgnciClaimPolicyTaskDO>()
                        .eq(CgnciClaimPolicyTaskDO::getTaskNo, task.getTaskNo()));
        CgnciClaimPolicyTaskDO claimPolicy = new CgnciClaimPolicyTaskDO();
        CgnciBusinessInsuranceVO bizInsuranceVO = policyInfo.getBusinessInsuranceVO();
        claimPolicy.setTaskNo(task.getTaskNo());
        claimPolicy.setCurrentPolicyId(bizInsuranceVO.getInsuranceId());
        claimPolicy.setCaseNo(task.getCaseNo());
        claimPolicy.setPolicyNo(policyInfo.getBusinessInsuranceVO().getBusinessNo());
        claimPolicy.setRiskSubType(bizInsuranceVO.getRiskSubType());
        claimPolicy.setRiskSubTypeCode(bizInsuranceVO.getRiskSubTypeCode());
        claimPolicy.setProjectName(bizInsuranceVO.getProjectName());
        claimPolicy.setProjectNo(bizInsuranceVO.getProjectNo());
        claimPolicy.setCedingCompany(policyInfo.getReinsurers());
        claimPolicy.setAcceptCompany(policyInfo.getAcceptCompany());
        if (VerifyUtils.isNotEmpty(policyInfo.getStatVOList())) {
            claimPolicy.setShareRatio(policyInfo.getStatVOList().get(0).getShareRatio());
            claimPolicy.setCededRatio(policyInfo.getStatVOList().get(0).getCededRatio());
            claimPolicy.setNetSelfShare(policyInfo.getStatVOList().get(0).getRetentionRatio());
        }
        claimPolicy.setDeductibleDesc("无"); // todo。。。
        claimPolicy.setPremiumReceived("已支付"); // todo 。。。
        if (Objects.equals(Boolean.TRUE, policyInfo.getIsDivideOut())) {
            claimPolicy.setReinsureFlag(YesOrNoEnum.YES.getCode());
        } else {
            claimPolicy.setReinsureFlag(YesOrNoEnum.NO.getCode());
        }
        claimPolicy.setPolicyStartDate(policyInfo.getBusinessInsuranceVO().getStartDate());
        claimPolicy.setPolicyEndDate(policyInfo.getBusinessInsuranceVO().getEndDate());
        claimPolicy.setPolicyYear(policyInfo.getBusinessInsuranceVO().getBusinessYear());
        claimPolicy.setPolicyCurrency(policyInfo.getBusinessInsuranceVO().getCurrency());
        if (Objects.isNull(claimPolicyDO)) {
            claimPolicy.setCreator(task.getCreator());
            claimPolicy.setUpdater(task.getUpdater());
            claimPolicyTaskMapper.insert(claimPolicy);
        } else {
            claimPolicy.setId(claimPolicyDO.getId());
            claimPolicy.setUpdateTime(new Date());
            claimPolicyTaskMapper.updateById(claimPolicy);
        }
    }

    private CgnciClaimCaseTaskDO getCaseTask(String taskNo) {
        LambdaQueryWrapper<CgnciClaimCaseTaskDO> param = new LambdaQueryWrapper<CgnciClaimCaseTaskDO>()
                .eq(CgnciClaimCaseTaskDO::getTaskNo, taskNo);
        return getBaseMapper().selectOne(param);
    }

    private CgnciClaimCaseDO getCase(String caseNo) {
        LambdaQueryWrapper<CgnciClaimCaseDO> param = new LambdaQueryWrapper<CgnciClaimCaseDO>()
                .eq(CgnciClaimCaseDO::getCaseNo, caseNo);
        return cgnciClaimCaseMapper.selectOne(param);
    }

    private CgnciClaimCaseTaskDO buildCreate(UserEntity user, CgnciBusinessInsuranceMainVO policyInfo) {
        CgnciClaimCaseTaskDO task = new CgnciClaimCaseTaskDO();
        task.setOriginalCurrency(policyInfo.getBusinessInsuranceVO().getCurrency());
        task.setReportCurrency(policyInfo.getBusinessInsuranceVO().getCurrency());
        task.setEstimateCurrency(policyInfo.getBusinessInsuranceVO().getCurrency());
        task.setCompensationCurrency(policyInfo.getBusinessInsuranceVO().getCurrency());

        task.setTaskNo(generateTaskNo());
        // 立案号:C+保单号+4位数字序号
        String businessNo = cgnciCodeTypeService.getBusinessNo("claims", "number");
        task.setCaseNo("C" + policyInfo.getBusinessInsuranceVO().getBusinessNo() + businessNo);
        task.setPolicyNo(policyInfo.getBusinessInsuranceVO().getBusinessNo());
        task.setTaskType(ClaimTaskTypeEnum.FILING.getCode());
        task.setTaskStatus(ClaimTaskStatusEnum.INPUT.getCode());
        task.setCaseStatus(ClaimCaseStatusEnum.NO_CLAIM.getCode());
        task.setCreator(user.getNameAndCode());
        task.setUpdater(user.getNameAndCode());
        return task;
    }

    private ApprovalInfoVO createCaseFlow(UserEntity user, CgnciClaimCaseTaskDO task) {
        FlowTaskCreateDTO flowTask = new FlowTaskCreateDTO();
        flowTask.setApprovalConfigGroupId(ClaimFlowEnum.CLAIM_CASE.getCode());
        flowTask.setFormId(task.getTaskNo());
        flowTask.setFormNo(task.getTaskNo());
        return approvalService.create(flowTask);
    }

    private CgnciClaimCaseCreateResultVO createCaseCheckPass(CgnciBusinessInsuranceMainVO policyInfo, Boolean confirm) {
        CgnciClaimCaseCreateResultVO response = CgnciClaimCaseCreateResultVO.builder().policyNo(policyInfo.getBusinessInsuranceVO().getBusinessNo()).build();
        Assert.notNull(policyInfo, "查询不到该保单。");
        Assert.notNull(policyInfo.getBusinessInsuranceVO(), "保单基本数据缺失。");
        CgnciBusinessInsuranceVO bizInsurance = policyInfo.getBusinessInsuranceVO();
        response.setProjectName(bizInsurance.getProjectName());
        String policyStatus = bizInsurance.getStatus();
        // 仅保单状态为“已生效”可新增立案  保单状态{保单状态}，不可新增立案。
        Assert.isTrue(Objects.equals(policyStatus, "3"), String.format(" 保单状态:%s，不可新增立案。", policyStatus));
        // 保单存在在途批改，不可新增立案  批改{批单号}未完成，不可新增立案。
        if (policyInfo.getIsEndorsement()) {
            throw new GlobalException(ResponseCodeEnum.HTTP_REQUEST_SERVICE_ERROR, "保单存在在途批改，不可新增立案");
        }
        if (!Objects.equals(Boolean.TRUE, confirm)) {
            // 保单分入保费未实收，提示是否继续新增立案；分入保费分期场景校验缴费截止日期在当前系统时间以前的分期状态； 保费未实收，是否继续新增立案？
            // 若当前保单有未结案案件，新增立案时需提示 保单包含以下未结案案件，是否继续新增立案？ {立案号1}-{案件名称1}
            LambdaQueryWrapper<CgnciClaimCaseDO> param = new LambdaQueryWrapper<CgnciClaimCaseDO>()
                    .eq(CgnciClaimCaseDO::getPolicyNo, policyInfo.getBusinessInsuranceVO().getBusinessNo())
                    .eq(CgnciClaimCaseDO::getDeleted, "N")
                    .notIn(CgnciClaimCaseDO::getCaseStatus, excludeCaseStatusList);
            List<CgnciClaimCaseDO> caseList = cgnciClaimCaseMapper.selectList(param);
            if (CollectionUtils.isNotEmpty(caseList)) {
                StringBuilder notice = new StringBuilder("保单包含以下未结案案件，是否继续新增立案？");
                StringBuilder msg = new StringBuilder();
                for (CgnciClaimCaseDO item : caseList) {
                    if (StringUtils.isNotBlank(item.getCaseName())) {
                        msg.append(item.getCaseNo()).append(ClaimConstant.LINE).append(item.getCaseName())
                                .append(ClaimConstant.SEMICOLON);
                    } else {
                        msg.append(item.getCaseNo()).append(ClaimConstant.SEMICOLON);
                    }
                }
                notice.append(msg);
                response.setConfirmMessageList(Collections.singletonList(notice.toString()));
            }
        }
        return response;
    }


    @Override
    public CgnciClaimCaseTaskDO copyCreateCaseTask(UserEntity user, String caseNo, String taskNo, String taskType) {
        StopWatch sw = new StopWatch();
        sw.start("copyCreateCaseTask");
        CgnciClaimCaseVO caseDetail = cgnciClaimCaseService.detail(caseNo);
        sw.stop();
        sw.start("cgnciClaimCaseTaskMapper.insert");
        CgnciClaimCaseTaskDO caseTask = ConvertUtils.convert(caseDetail, CgnciClaimCaseTaskDO.class);
        caseTask.setCaseId(null);
        if (StringUtils.isNotBlank(taskNo)) {
            caseTask.setTaskNo(taskNo);
        } else {
            caseTask.setTaskNo(generateTaskNo());
        }
        caseTask.setCreator(user.getNameAndCode());
        caseTask.setUpdater(user.getNameAndCode());
        caseTask.setTaskType(taskType);
        caseTask.setTaskStatus(ClaimTaskStatusEnum.INPUT.getCode());
        cgnciClaimCaseTaskMapper.insert(caseTask);
        sw.stop();
        sw.start("copySaveCasePolicyInfo");
        copySaveCasePolicyInfo(caseTask);
        sw.stop();
        if (StringUtils.isEmpty(taskNo)) {
            sw.start("copySaveReserve");
            copySaveReserve(caseTask);
            sw.stop();
        }
        sw.start("copySaveSettlement");
        copySaveSettlement(caseDetail, caseTask);
        sw.stop();
        sw.start("copySaveAttachment");
        copySaveAttachment(caseDetail, caseTask);
        sw.stop();
        log.debug("复制创建copyCreateCaseTask 总耗时：{} 耗时详情：{}", sw.getTotalTimeSeconds(), sw.prettyPrint());
        return caseTask;
    }

    private void copySaveCasePolicyInfo(CgnciClaimCaseTaskDO task) {
        String policyNo = task.getPolicyNo();
        CgnciClaimPolicyTaskDO claimPolicyDO = claimPolicyTaskMapper.selectOne(
                new LambdaQueryWrapper<CgnciClaimPolicyTaskDO>()
                        .eq(CgnciClaimPolicyTaskDO::getTaskNo, task.getTaskNo()));
        CgnciBusinessInsuranceMainVO policyInfo = policyService.getPolicyInfo(policyNo);
        if (policyInfo == null || Objects.isNull(policyInfo.getBusinessInsuranceVO())) {
            return;
        }
        CgnciClaimPolicyTaskDO claimPolicy = new CgnciClaimPolicyTaskDO();
        CgnciBusinessInsuranceVO bizInsuranceVO = policyInfo.getBusinessInsuranceVO();
        claimPolicy.setTaskNo(task.getTaskNo());
        claimPolicy.setCurrentPolicyId(bizInsuranceVO.getInsuranceId());
        claimPolicy.setCaseNo(task.getCaseNo());
        claimPolicy.setPolicyNo(policyNo);
        claimPolicy.setRiskSubType(bizInsuranceVO.getRiskSubType());
        claimPolicy.setRiskSubTypeCode(bizInsuranceVO.getRiskSubTypeCode());
        claimPolicy.setProjectName(bizInsuranceVO.getProjectName());
        claimPolicy.setProjectNo(bizInsuranceVO.getProjectNo());
        claimPolicy.setCedingCompany(policyInfo.getReinsurers());
        claimPolicy.setAcceptCompany(policyInfo.getAcceptCompany());
        if (VerifyUtils.isNotEmpty(policyInfo.getStatVOList())) {
            claimPolicy.setShareRatio(policyInfo.getStatVOList().get(0).getShareRatio());
            claimPolicy.setCededRatio(policyInfo.getStatVOList().get(0).getCededRatio());
            claimPolicy.setNetSelfShare(policyInfo.getStatVOList().get(0).getRetentionRatio());
        }
        if (Objects.equals(Boolean.TRUE, policyInfo.getIsDivideOut())) {
            claimPolicy.setReinsureFlag(YesOrNoEnum.YES.getCode());
        } else {
            claimPolicy.setReinsureFlag(YesOrNoEnum.NO.getCode());
        }
        claimPolicy.setPolicyStartDate(policyInfo.getBusinessInsuranceVO().getStartDate());
        claimPolicy.setPolicyEndDate(policyInfo.getBusinessInsuranceVO().getEndDate());
        claimPolicy.setPolicyYear(policyInfo.getBusinessInsuranceVO().getBusinessYear());
        claimPolicy.setPolicyCurrency(policyInfo.getBusinessInsuranceVO().getCurrency());
        if (Objects.isNull(claimPolicyDO)) {
            claimPolicy.setCreator(task.getCreator());
            claimPolicy.setUpdater(task.getUpdater());
            claimPolicyTaskMapper.insert(claimPolicy);
        } else {
            claimPolicy.setId(claimPolicyDO.getId());
            claimPolicy.setUpdateTime(new Date());
            claimPolicyTaskMapper.updateById(claimPolicy);
        }
    }

    private void copySaveReserve(CgnciClaimCaseTaskDO caseTask) {
        String caseNo = caseTask.getCaseNo();
        String taskNo = caseTask.getTaskNo();
        LambdaQueryWrapper<CgnciClaimReserveDO> query = new LambdaQueryWrapper<CgnciClaimReserveDO>()
                .eq(CgnciClaimReserveDO::getCaseNo, caseNo);
        List<CgnciClaimReserveDO> reserveDOS = reserveMapper.selectList(query);
        if (CollectionUtils.isEmpty(reserveDOS)) return;
        for (CgnciClaimReserveDO reserve : reserveDOS) {
            CgnciClaimReserveTaskDO reserveTaskDO = ConvertUtils.convert(reserve, CgnciClaimReserveTaskDO.class);
            reserveTaskDO.setReserveId(null);
            reserveTaskDO.setTaskNo(taskNo);
            reserveTaskDO.setCreator(caseTask.getCreator());
            reserveTaskDO.setUpdater(caseTask.getUpdater());
            reserveTaskMapper.insert(reserveTaskDO);
            saveReserveDetail(taskNo, reserve, reserveTaskDO);
        }
    }

    private void copySaveSettlement(CgnciClaimCaseVO caseDetail, CgnciClaimCaseTaskDO caseTask) {
        String caseNo = caseTask.getCaseNo();
        String taskNo = caseTask.getTaskNo();
        if (CollectionUtils.isEmpty(caseDetail.getSettlements())) return;
        for (CgnciClaimSettlementVO settlement : caseDetail.getSettlements()) {
            CgnciClaimSettlementTaskDO settlementTask = ConvertUtils.convert(settlement, CgnciClaimSettlementTaskDO.class);
            settlementTask.setSettlementId(null);
            settlementTask.setTaskNo(taskNo);
            settlementTask.setCaseNo(caseNo);
            settlementTask.setCreator(caseTask.getCreator());
            settlementTask.setUpdater(caseTask.getUpdater());
            claimSettlementTaskMapper.insert(settlementTask);
            copySaveReinsurer(settlement, settlementTask);
        }
    }

    private void copySaveAttachment(CgnciClaimCaseVO caseDetail, CgnciClaimCaseTaskDO caseTask) {
        if (CollectionUtils.isEmpty(caseDetail.getAccessoryList())) return;
        List<CgnciAccessoryDO> accessoryList = ConvertUtils.convert(caseDetail.getAccessoryList(), CgnciAccessoryDO.class);
        for (CgnciAccessoryDO accessory : accessoryList) {
            accessory.setAccId(null);
            accessory.setUploadNode("claim-task");
            accessory.setBusinessNo(caseTask.getTaskNo());
            accessory.setBusinessId(caseTask.getCaseId());
            accessory.setCreateUser(caseTask.getCreator());
            accessory.setUpdateUser(caseTask.getUpdater());
            accessory.setCreateTime(new Date());
            accessory.setUpdateTime(new Date());
            cgnciAccessoryMapper.insert(accessory);
        }
    }

    private void saveReserveDetail(String taskNo, CgnciClaimReserveDO reserve, CgnciClaimReserveTaskDO reserveTaskDO) {
        LambdaQueryWrapper<CgnciClaimReserveDetailDO> queryDetail = new LambdaQueryWrapper<CgnciClaimReserveDetailDO>()
                .eq(CgnciClaimReserveDetailDO::getReserveId, reserve.getReserveId());
        List<CgnciClaimReserveDetailDO> reserveDetailDOS = reserveDetailMapper.selectList(queryDetail);
        if (CollectionUtils.isEmpty(reserveDetailDOS)) return;
        for (CgnciClaimReserveDetailDO reserveDetail : reserveDetailDOS) {
            CgnciClaimReserveDetailTaskDO detailTaskDO = ConvertUtils.convert(reserveDetail, CgnciClaimReserveDetailTaskDO.class);
            detailTaskDO.setDetailId(null);
            detailTaskDO.setReserveId(reserveTaskDO.getReserveId());
            detailTaskDO.setTaskNo(taskNo);
            detailTaskDO.setCreator(reserveTaskDO.getCreator());
            detailTaskDO.setUpdater(reserveTaskDO.getUpdater());
            reserveDetailTaskMapper.insert(detailTaskDO);
        }
    }

    private void copySaveReinsurer(CgnciClaimSettlementVO settlementVO, CgnciClaimSettlementTaskDO settlementTask) {
        Long settlementId = settlementTask.getSettlementId();
        String caseNo = settlementTask.getCaseNo();
        String taskNo = settlementTask.getTaskNo();
        if (CollectionUtils.isNotEmpty(settlementVO.getIntoSettlementList())) {
            for (CgnciClaimSettlementVO.ReinsurerVO reinsurerVO : settlementVO.getIntoSettlementList()) {
                CgnciClaimSettlementReinsurerTaskDO reinsurerDO = ConvertUtils.convert(reinsurerVO,
                        CgnciClaimSettlementReinsurerTaskDO.class);
                reinsurerDO.setReinsurerId(null);
                reinsurerDO.setCaseNo(caseNo);
                reinsurerDO.setTaskNo(taskNo);
                reinsurerDO.setCreator(settlementTask.getCreator());
                reinsurerDO.setUpdater(settlementTask.getUpdater());
                reinsurerDO.setSettlementId(settlementId);
                settlementReinsurerTaskMapper.insert(reinsurerDO);
                if (CollectionUtils.isEmpty(reinsurerVO.getDetails())) continue;
                for (CgnciClaimSettlementVO.DetailVO detail : reinsurerVO.getDetails()) {
                    CgnciClaimSettlementDetailTaskDO detailTaskDO = new CgnciClaimSettlementDetailTaskDO();
                    BeanUtils.copyProperties(detail, detailTaskDO);
                    detailTaskDO.setDetailId(null);
                    detailTaskDO.setTaskNo(taskNo);
                    detailTaskDO.setCaseNo(caseNo);
                    detailTaskDO.setCreator(settlementTask.getCreator());
                    detailTaskDO.setUpdater(settlementTask.getUpdater());
                    detailTaskDO.setReinsurerId(reinsurerDO.getReinsurerId());
                    settlementDetailTaskMapper.insert(detailTaskDO);
                }
            }
        }
    }


    private void saveLog(String caseNo, OperationTypeEnum typeEnum, String creator, String... remarks) {
        Assert.notNull(typeEnum, "操作类型必填");
        CgnciOperationLogsDTO saveLog = new CgnciOperationLogsDTO();
        if (Objects.nonNull(remarks)) {
            String content = String.join(ClaimConstant.SEMICOLON, remarks);
            saveLog.setContent(content);
        }
        Date now = new Date();
        saveLog.setBizNo(caseNo);
        saveLog.setBizType(BusinessScenariosEnum.CLAIM.getCode());
        saveLog.setOperationType(typeEnum.getCode());
        saveLog.setCreateTime(now);
        saveLog.setCreator(creator);
        saveLog.setUpdateTime(now);
        saveLog.setUpdater(creator);
        cgnciOperationLogsService.saveLog(saveLog);
    }

    private void saveErrorMessage(String taskNo, String content, String businessSceneType, String contentType) {
        CgnciClaimAlertInfoDO info = new CgnciClaimAlertInfoDO();
        info.setContent(content);
        info.setContentType(contentType);
        info.setBusinessNo(taskNo);
        info.setAlertType(AlertInfoTypeEnum.ERROR.getCode());
        info.setBusinessScene(BusinessScenariosEnum.CLAIM.getCode());
        info.setBusinessSceneType(businessSceneType);
        cgnciClaimAlertInfoService.clearHistoryAndSave(info);
    }
}
